package com.leador.map.location.util;

import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.Proxy;
import android.telephony.TelephonyManager;

import com.leador.map.location.Const;

import org.apache.http.Header;
import org.apache.http.HttpHost;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ConnectTimeoutException;
import org.apache.http.conn.params.ConnRouteParams;
import org.apache.http.conn.scheme.PlainSocketFactory;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.SingleClientConnManager;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpParams;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.zip.GZIPInputStream;

/**
 *
 */
public class NetUtil {
    private static NetUtil instance = null;

    private NetUtil() {
        //
    }

    /**
     * 获取实例
     *
     * @return 网络工具类实例
     */
    public synchronized static NetUtil getInstance() {
        if (instance == null) {
            instance = new NetUtil();
        }
        return instance;
    }

    /**
     * 获取手机联网方式
     *
     * @param ni
     * @return int
     */
    public static int getNetworkType(NetworkInfo ni) {
        int iNetworkType = -1;
        if (ni == null) {
            iNetworkType = -1;
        } else if (!ni.isAvailable()) {
            iNetworkType = -1;
        } else if (!ni.isConnected()) {
            iNetworkType = -1;
        } else {
            iNetworkType = ni.getType();
        }
        return iNetworkType;
    }

    /**
     * 获取手机网络制式
     *
     * @param tm
     * @return String
     */
    public static String getNetType(TelephonyManager tm) {
        int iNetType = 0;
        if (tm != null) {
            iNetType = tm.getNetworkType();
        }
        return Const.saPhoneNets.get(iNetType, "UNKNOWN");
    }

    /**
     * 判断返回数据是否经过GZIP
     *
     * @param httpResp
     * @return boolean
     */
    private static boolean respGzipped(HttpResponse httpResp) {
        Header h = httpResp.getFirstHeader("Content-Encoding");
        if (h != null && h.getValue().equalsIgnoreCase("gzip")) {
            return true;
        }
        return false;
    }

    /**
     *
     * @param url
     * @param content
     * @param ctx
     * @param cm
     * @return
     * @throws Exception
     */
    public synchronized String post(String url, String content, Context ctx,
                                       ConnectivityManager cm) throws Exception {
        String strResult = "";
        NetworkInfo ni = cm.getActiveNetworkInfo();
        int iNetworkType = getNetworkType(ni);
        Utils.writeCat("net type:", iNetworkType);
        if (iNetworkType == -1) {
            Utils.writeCat("no net available");
            return null;
        }
        //
        HttpClient hc = null;
        HttpPost hp = null;
        StringEntity se = null;
        HttpResponse hr = null;
        InputStream is = null;
        InputStreamReader isr = null;
        BufferedReader br = null;
        //
        try {
            hc = getClient(ctx, ni);
            //
            hp = new HttpPost(url);
            //
            se = new StringEntity(content, Const.locCharacterEncode);
            se.setContentType("application/octet-stream");
            hp.setEntity(se);
            hr = hc.execute(hp);
            int iStatusCode = hr.getStatusLine().getStatusCode();
            Utils.writeCat("http resp status code:", iStatusCode);
            if (iStatusCode == HttpStatus.SC_OK) {
                is = hr.getEntity().getContent();
                if (respGzipped(hr)) {
                    Utils.writeCat("resp is gzipped");
                    is = new GZIPInputStream(is);
                }
                isr = new InputStreamReader(is, Const.locCharacterEncode);
                br = new BufferedReader(isr, 2 * 1024);
                StringBuilder sb = new StringBuilder();
                String strLine = "";
                while ((strLine = br.readLine()) != null) {
                    sb.append(strLine);
                }
                strResult = sb.toString();
                sb.delete(0, sb.length());
                sb = null;
            }
        } catch (java.net.UnknownHostException e) {
            Utils.writeCat("unknown host e");
        } catch (java.net.SocketException e) {
            Utils.writeCat("socket e");
        } catch (java.net.SocketTimeoutException e) {
            Utils.writeCat("socket timeout e");
        } catch (ConnectTimeoutException e) {
            Utils.writeCat("connect timeout e");
        } finally {
            if (hp != null) {
                hp.abort();
                hp = null;
            }
            if (hc != null) {
                hc.getConnectionManager().shutdown();
                hc = null;
            }
            se = null;
            hr = null;
            if (is != null) {
                is.close();
                is = null;
            }
            if (isr != null) {
                isr.close();
                isr = null;
            }
            if (br != null) {
                br.close();
                br = null;
            }
        }
        return (strResult.length() < 1 ? null : strResult);
    }
    /**
     * 向服务器发送XML字符串请求，获取返回结果
     *
     * @param url
     * @param content
     * @param ctx
     * @param cm
     * @return String
     */
    public synchronized String postXml(String url, String content, Context ctx,
                                       ConnectivityManager cm) throws Exception {
        String strResult = "";
        NetworkInfo ni = cm.getActiveNetworkInfo();
        int iNetworkType = getNetworkType(ni);
        Utils.writeCat("net type:", iNetworkType);
        if (iNetworkType == -1) {
            Utils.writeCat("no net available");
            return null;
        }
        //
        HttpClient hc = null;
        HttpPost hp = null;
        StringEntity se = null;
        HttpResponse hr = null;
        InputStream is = null;
        InputStreamReader isr = null;
        BufferedReader br = null;
        //
        try {
            hc = getClient(ctx, ni);
            //
            hp = new HttpPost(url);
            //
            se = new StringEntity(content, Const.locCharacterEncode);
            se.setContentType("text/xml");
            String str = null;
            str = "application/soap+xml;charset=" + Const.locCharacterEncode;
            hp.setHeader("Content-Type", str);
            str = null;
            hp.setEntity(se);
            hr = hc.execute(hp);
            int iStatusCode = hr.getStatusLine().getStatusCode();
            Utils.writeCat("http resp status code:", iStatusCode);
            if (iStatusCode == HttpStatus.SC_OK) {
                is = hr.getEntity().getContent();
                if (respGzipped(hr)) {
                    Utils.writeCat("resp is gzipped");
                    is = new GZIPInputStream(is);
                }
                isr = new InputStreamReader(is, Const.locCharacterEncode);
                br = new BufferedReader(isr, 2 * 1024);
                StringBuilder sb = new StringBuilder();
                String strLine = "";
                while ((strLine = br.readLine()) != null) {
                    sb.append(strLine);
                }
                strResult = sb.toString();
                sb.delete(0, sb.length());
                sb = null;
            }
        } catch (java.net.UnknownHostException e) {
            Utils.writeCat("unknown host e");
        } catch (java.net.SocketException e) {
            Utils.writeCat("socket e");
        } catch (java.net.SocketTimeoutException e) {
            Utils.writeCat("socket timeout e");
        } catch (ConnectTimeoutException e) {
            Utils.writeCat("connect timeout e");
        } finally {
            if (hp != null) {
                hp.abort();
                hp = null;
            }
            if (hc != null) {
                hc.getConnectionManager().shutdown();
                hc = null;
            }
            se = null;
            hr = null;
            if (is != null) {
                is.close();
                is = null;
            }
            if (isr != null) {
                isr.close();
                isr = null;
            }
            if (br != null) {
                br.close();
                br = null;
            }
        }
        return (strResult.length() < 1 ? null : strResult);
    }

    /**
     * 获取HTTPCLIENT实例
     *
     * @param ctx
     * @param ni
     * @return
     */
    @SuppressWarnings("deprecation")
    private HttpClient getClient(Context ctx, NetworkInfo ni) throws Exception {
        HttpParams httpParams = new BasicHttpParams();
        String strHost = null;
        int iPort = -1;
        if (ni.getType() == ConnectivityManager.TYPE_WIFI) {
            strHost = Proxy.getHost(ctx);
            iPort = Proxy.getPort(ctx);
        } else if (ni.getType() == ConnectivityManager.TYPE_MOBILE) {
            strHost = Proxy.getDefaultHost();
            iPort = Proxy.getDefaultPort();
        }
        if (needProxy(strHost, iPort)) {
            HttpHost httpHost = new HttpHost(strHost, iPort);
            httpParams.setParameter(ConnRouteParams.DEFAULT_PROXY, httpHost);
        }
        Utils.setTimeOut(httpParams, Const.iTimeout);
        SchemeRegistry sr = new SchemeRegistry();
        PlainSocketFactory psf = null;
        psf = PlainSocketFactory.getSocketFactory();
        Scheme scheme = new Scheme("http", psf, 80);
        sr.register(scheme);
        SingleClientConnManager sccm = null;
        sccm = new SingleClientConnManager(httpParams, sr);
        HttpClient hc = new DefaultHttpClient(sccm, httpParams);
        return hc;
    }

    /**
     * 判断是否需要通过代理联网
     *
     * @param strHost
     * @param iPort
     * @return boolean
     */
    private boolean needProxy(String strHost, int iPort) {
        return (strHost != null && strHost.length() > 0 && iPort != -1);
    }
}